#include "memory.h"
#include "globalconst.h"
#include "keyboard.h"
#include "monitor.h"

Memory* Memory::instance = 0;
//
bool Memory::ok = false;
const quint32 Memory::KBSR_ADDRESS = QString("FFFF0000").toLongLong(&ok, 16);
const quint32 Memory::KBDR_ADDRESS = QString("FFFF0004").toLongLong(&ok, 16);
const quint32 Memory::DSR_ADDRESS = QString("FFFF0008").toLongLong(&ok, 16);
const quint32 Memory::DDR_ADDRESS = QString("FFFF000C").toLongLong(&ok, 16);
const quint32 Memory::MCR_ADDRESS = QString("FFFF00F8").toLongLong(&ok, 16);


Memory::Memory(QObject *parent) : QObject(parent)
{
}

Memory::~Memory()
{
}

Memory* Memory::getInstance(QObject *parent)
{
    if(instance == 0)
    {
        instance = new Memory(parent);
    }
    return instance;
}

void Memory::write(quint32 address, const QString &content)
{
    Q_ASSERT(content.size() == 8);
    //
    if(isSpecialAddress(address)) {
        writeMemoryMapping(address, content);
    }
    else
    {
        if(content == GlobalConst::EMPTY_REGISTER)
        {
            memory.remove(address);
        }
        else
        {
            memory.insert(address, content);
        }
        emit dataChanged(address);
    }
}

QString Memory::read(quint32 address) const
{
    if(isSpecialAddress(address)) {
        return readMemoryMapping(address);
    }
    else
    {
        return memory.value(address, GlobalConst::EMPTY_MEMORY);
    }
}

QString Memory::readMemoryMapping(quint32 address) const
{
    if(address >= KBSR_ADDRESS && address < KBSR_ADDRESS + 4)
    {
        KeyBoard* keyboard = KeyBoard::getInstance();
        return keyboard->getKBSR(address - KBSR_ADDRESS);
    }
    else if(address >= KBDR_ADDRESS && address < KBDR_ADDRESS + 4)
    {
        KeyBoard* keyboard = KeyBoard::getInstance();
        return keyboard->getKBDR(address - KBDR_ADDRESS);
    }
    else if(address >= DSR_ADDRESS && address < DSR_ADDRESS + 4)
    {
        Monitor* monitor = Monitor::getInstance();
        return monitor->getDSR(address - DSR_ADDRESS);
    }
    else if(address >= DDR_ADDRESS && address < DDR_ADDRESS + 4)
    {
        return GlobalConst::EMPTY_MEMORY;
    }
    else
    {
        return GlobalConst::EMPTY_MEMORY;
    }
}

void Memory::writeMemoryMapping(quint32 address, const QString& value)
{
    if(address >= KBSR_ADDRESS && address < KBSR_ADDRESS + 4)
    {
    }
    else if(address >= KBDR_ADDRESS && address < KBDR_ADDRESS + 4)
    {
    }
    else if(address >= DSR_ADDRESS && address < DSR_ADDRESS + 4)
    {
    }
    else if(address >= DDR_ADDRESS && address < DDR_ADDRESS + 4)
    {
        Monitor* monitor = Monitor::getInstance();
        monitor->setDDR(value, address - DDR_ADDRESS);
    }
}

bool Memory::isSpecialAddress(quint32 address) const
{
    if((address >= KBSR_ADDRESS && address < KBSR_ADDRESS + 4) ||
       (address >= KBDR_ADDRESS && address < KBDR_ADDRESS + 4) ||
       (address >= DSR_ADDRESS && address < DSR_ADDRESS + 4) ||
       (address >= DDR_ADDRESS && address < DDR_ADDRESS + 4) ||
       (address >= MCR_ADDRESS && address < MCR_ADDRESS + 4))
    {
        return true;
    }
    else
    {
        return false;
    }
}
